<?php
/**
 * Util
 *
 * @category	Util
 * @package		dayscript.util
 * @subpackage
 * @author		Nelson Daza <ndaza@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license
 * @version		1.0
 * @version		$Revision: 0 $
 * @filesource
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses
 * @since		1.0
 * @modifiedby	$LastChangedBy: Nelson Daza $
 * @modified	$Date: 2009-09-15 $
 */

namespace dayscript\util;

/**
 * Util
 *
 * Singleton
 *
 * @category	Util
 * @package		dayscript.util
 * @subpackage
 * @author		Nelson Daza <ndaza@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license
 * @version		1.0
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses
 * @since		1.0
 * @modifiedby	$LastChangedBy: Nelson Daza $
 * @modified	$Date: 2009-09-15 $
 * @todo utf32 support
 */
class Util	{
	/**
	 * Util constructor
	 * @return \dayscript\util\Util
	 */
	private function __construct( )	{

	}
	/**
	 * Vector validation to check if an array is a struct or not
	 * A little bit nasty but PHP uses associative arrays and vector arrays as equals
	 * @return boolean $isVector
	 */
	public static function isVector( $data )	{
		return ( \is_array( $data ) && \count( \array_diff_key( $data, \range( 0, \count( $data ) - 1 ) ) ) == 0 );
	}
	/**
	 * Convert a char from UTF-16 to UTF-8
	 *
	 * Normally should be handled by mb_convert_encoding, but provides a slower method for installations that lacks the multibyte string extension.
	 * @param string $utf16 UTF-16 character
	 * @return string UTF-8 character
	 */
	public static function charUTF16ToUTF8( $utf16 )	{
		// Hopefully ...
		if( \function_exists( 'mb_convert_encoding' ) )
		return \mb_convert_encoding( $utf16, 'UTF-8', 'UTF-16' );

		$bytes = ( \ord( $utf16{0} ) << 8 ) | \ord( $utf16{1} );

		// This case should never be reached, because we are in ASCII range
		if( ( 0x7F & $bytes ) == $bytes )
		return \chr( 0x7F & $bytes );
		// Return a 2-byte UTF-8 character
		if( ( 0x07FF & $bytes ) == $bytes )
		return \chr( 0xC0 | ( ( $bytes >> 6 ) & 0x1F ) ) . \chr( 0x80 | ( $bytes & 0x3F ) );
		// Return a 3-byte UTF-8 character
		if( ( 0xFFFF & $bytes ) == $bytes )
		return \chr( 0xE0 | ( ( $bytes >> 12 ) & 0x0F ) ) . \chr( 0x80 | ( ( $bytes >> 6 ) & 0x3F ) ) . \chr( 0x80 | ( $bytes & 0x3F ) );

		// Case like utf-32
		return '';
	}
	/**
	 * Convert a char from UTF-8 to UTF-16
	 *
	 * Normally should be handled by mb_convert_encoding, but provides a slower method for installations that lacks the multibyte string extension.
	 *
	 * @param string $utf8 UTF-8 character
	 * @return string UTF-16 character
	 */
	public static function charUTF8ToUTF16( $utf8 )	{
		// Hopefully ...
		if( \function_exists( 'mb_convert_encoding' ) )
		return \mb_convert_encoding( $utf8, 'UTF-16', 'UTF-8' );
		switch( \strlen( $utf8 ) )	{
			case 1:
				// this case should never be reached, because we are in ASCII range
				return $utf8;
			case 2:
				// return a UTF-16 character from a 2-byte UTF-8 char
				return \chr( 0x07 & ( \ord( $utf8{0} ) >> 2 ) ) . \chr( ( 0xC0 & ( \ord( $utf8{0} ) << 6 ) ) | ( 0x3F & \ord( $utf8{1} ) ) );
			case 3:
				// return a UTF-16 character from a 3-byte UTF-8 char
				return \chr( ( 0xF0 & ( \ord( $utf8{0} ) << 4 ) ) | ( 0x0F & ( \ord( $utf8{1} ) >> 2 ) ) ) . \chr( ( 0xC0 & ( \ord( $utf8{1} ) << 6 ) ) | ( 0x7F & \ord( $utf8{2} ) ) );
		}
		// Case like utf-32
		return '';
	}
}
